package com.zxy.supplier_system.server.xinyuan.service

import com.zxy.supplier_system.server.utils.orElse404
import com.zxy.supplier_system.server.xinyuan.controller.XinyuanGoodsController
import com.zxy.supplier_system.server.xinyuan.controller.XinyuanGoodsController.QueryGoodsListRequest
import com.zxy.supplier_system.server.xinyuan.entity.XinyuanGoods
import com.zxy.supplier_system.server.xinyuan.entity.XinyuanGoodsBrand
import com.zxy.supplier_system.server.xinyuan.entity.XinyuanGoodsCategory
import com.zxy.supplier_system.server.xinyuan.entity.toIntIdAndName
import com.zxy.supplier_system.server.xinyuan.repository.XinyuanGoodsBrandRepository
import com.zxy.supplier_system.server.xinyuan.repository.XinyuanGoodsCategoryRepository
import com.zxy.supplier_system.server.xinyuan.repository.XinyuanGoodsRepository
import jakarta.persistence.criteria.Predicate
import org.springframework.data.domain.Page
import org.springframework.data.domain.Pageable
import org.springframework.data.jpa.domain.Specification
import org.springframework.data.repository.findByIdOrNull
import org.springframework.stereotype.Service
import org.springframework.transaction.annotation.Transactional

@Service
class XinyuanGoodsService(
    private val goodsRepository: XinyuanGoodsRepository,
    private val categoryRepository: XinyuanGoodsCategoryRepository,
    private val brandRepository: XinyuanGoodsBrandRepository
) {

    // 创建商品
    @Transactional
    fun createGoods(request: XinyuanGoodsController.CreateGoodsRequest): XinyuanGoodsController.GoodsDetailResponse {


        val category = categoryRepository.findByIdOrNull(request.categoryId).orElse404()
        val brand = brandRepository.findByIdOrNull(request.brandId).orElse404()

        val goods = XinyuanGoods().apply {
            model = request.model
            this.category = category
            this.brand = brand
            barcode = request.barcode
            energyEfficiencyLevel = request.energyEfficiencyLevel
        }

        val savedGoods = goodsRepository.save(goods)
        return toDetailResponse(savedGoods)
    }

    @Transactional(readOnly = true)
    // 获取商品列表（分页+动态查询）
    fun getGoodsList(
        request: XinyuanGoodsController.QueryGoodsListRequest,
        pageable: Pageable
    ): Page<XinyuanGoodsController.GoodsSummaryResponse> {
        val specification = createSearchSpecification(request)
        return goodsRepository.findAll(specification, pageable)
            .map { toSummaryResponse(it) }
    }

    // 获取商品详情
    fun getGoodsDetail(id: Int): XinyuanGoodsController.GoodsDetailResponse {
        return goodsRepository.findByIdOrNull(id)
            .orElse404()
            .let { toDetailResponse(it) }
    }

    // 更新商品
    @Transactional
    fun updateGoods(
        id: Int,
        request: XinyuanGoodsController.UpdateGoodsRequest
    ): XinyuanGoodsController.GoodsDetailResponse {
        val goods = goodsRepository.findByIdOrNull(id)
            .orElse404()

        request.model?.let { goods.model = it }
        request.categoryId?.let { goods.category = categoryRepository.findByIdOrNull(it).orElse404() }
        request.brandId?.let { goods.brand = brandRepository.findByIdOrNull(it).orElse404() }
        request.barcode?.let {
            goods.barcode = it
        }
        request.energyEfficiencyLevel?.let { goods.energyEfficiencyLevel = it }

        val updatedGoods = goodsRepository.save(goods)
        return toDetailResponse(updatedGoods)
    }

    // 删除商品
    @Transactional
    fun deleteGoods(id: Int) {
        goodsRepository.deleteById(id)
    }

    // 创建动态查询条件
    private fun createSearchSpecification(
        request: QueryGoodsListRequest,
    ): Specification<XinyuanGoods> {
        return Specification { root, _, criteriaBuilder ->
            val predicates = mutableListOf<Predicate>()

            if (request.categoryIds.isNotEmpty()) {
                val `in` = criteriaBuilder.`in`(
                    root.get<XinyuanGoodsCategory>("category").get<Int>("id")
                )
                request.categoryIds.forEach {
                    `in`.value(it)
                }
                predicates.add(`in`)
            }

            if (request.brandId.isNotEmpty()) {
                val `in` = criteriaBuilder.`in`(root.get<XinyuanGoodsBrand>("brand").get<Int>("id"))
                request.brandId.forEach {
                    `in`.value(it)
                }
            }


            request.brandId?.let {
                predicates.add(criteriaBuilder.like(root.get("barcode"), "%$it%"))
            }

            request.model?.let {
                predicates.add(criteriaBuilder.like(root.get("model"), "%$it%"))
            }

            criteriaBuilder.and(*predicates.toTypedArray())
        }
    }

    // 实体转摘要响应
    private fun toSummaryResponse(goods: XinyuanGoods): XinyuanGoodsController.GoodsSummaryResponse {
        return XinyuanGoodsController.GoodsSummaryResponse(
            id = goods.id,
            model = goods.model,
            category = goods.category.toIntIdAndName(),
            brand = goods.brand.toIntIdAndName(),
            barcode = goods.barcode,
        )
    }

    // 实体转详情响应
    private fun toDetailResponse(goods: XinyuanGoods): XinyuanGoodsController.GoodsDetailResponse {
        return XinyuanGoodsController.GoodsDetailResponse(
            id = goods.id,
            model = goods.model,
            category = XinyuanGoodsController.CategoryResponse(
                id = goods.category.id,
                name = goods.category.name
            ),
            brand = XinyuanGoodsController.BrandResponse(
                id = goods.brand.id,
                name = goods.brand.name
            ),
            barcode = goods.barcode,
            energyEfficiencyLevel = goods.energyEfficiencyLevel?.name
        )
    }

    @Transactional(readOnly = true)
    fun searchByKeyword(keyword: String, homeAppliance: Boolean): List<XinyuanGoodsController.SearchGoodsResponse> {
        return goodsRepository.searchByKeywordAndIsHomeAppliance(keyword, homeAppliance).map({
            XinyuanGoodsController.SearchGoodsResponse(
                it.id,
                it.model,
                it.category.toIntIdAndName(),
                it.brand.toIntIdAndName()
            )
        })
    }
}

